#ifndef LECTEURPHRASEAVECARBRE_H_
#define LECTEURPHRASEAVECARBRE_H_

#include "Symbole.h"
#include "LecteurSymbole.h"
#include "TableSymboles.h"
#include "Arbre.h"

#include <string>
using namespace std;

class LecteurPhraseAvecArbre {
public:
    LecteurPhraseAvecArbre(string nomFich); // Construit un lecteur de phrase pour interpreter
    //  le programme dans le fichier nomFich

    void analyse(); // Si le contenu du fichier est conforme à la grammaire,
    //   cette méthode se termine normalement et affiche un message "Syntaxe correcte".
    //   la table des symboles (ts) et l'arbre abstrait (arbre) auront été construits
    // Sinon, le programme sera interrompu (exit).

    inline TableSymboles getTs() {
        return ts;
    } // accesseur	

    inline Noeud* getArbre() {
        return arbre;
    } // accesseur

    void AfficheCompileCpp(string nomFichier = "main") {
        string nomF = "compile/" + nomFichier + ".cc";
        std::ofstream fichier(nomF.c_str(), ios::out | ios::trunc); // ouverture en écriture avec effacement du fichier ouvert
        if (fichier) {
            fichier << "#include <iostream>"<< endl<<"using namespace std;" 
<< endl;          
            fichier << "int main(){" << endl;
            cout << "int main(){" << endl;

            for (int i = 0; i < ts.size(); i++) {
                if (*ts[i] == "<VARIABLE>") {
                    cout << "int ";
                    fichier << "int ";
                    cout << ts[i]->getChaine();
                    fichier << ts[i]->getChaine();
                    cout << ";" << endl;
                    fichier << ";" << endl;
                }
            }
            getArbre()->AfficheCompileCpp(fichier, 1);
            cout << "}";
            fichier << "}" << endl;
            fichier.close();
        } else {
            cout << "Impossible d'ouvrir le fichier !" << endl;
        }
    }


private:
    LecteurSymbole ls; // le lecteur de symboles utilisé pour analyser le fichier
    TableSymboles ts; // la table des symboles valués
    Noeud* arbre; // l'arbre abstrait
    int nbErreurs;
    // implémentation de la grammaire
    Noeud* programme(); //   <programme> ::= debut <seqInst> fin FIN_FICHIER
    Noeud* seqInst(); //     <seqInst> ::= <inst> ; { <inst> ; }
    Noeud* inst(); //        <inst> ::= <affectation>
    Noeud* instSi();
    Noeud* instTq();
    Noeud* instPour(); // pour ( <VARIABLE>;<expBool>;<seqInst> ){<seqInst>}
    Noeud* instRepeter();
    Noeud* instlire();
    Noeud* instecrire();
    Noeud* affectation(); // <affectation> ::= <variable> = <expression>
    Noeud* expression(); //  <expression> ::= <facteur> { <opBinaire> <facteur> }
    Noeud* facteur(); //     <facteur> ::= <entier>  |  <variable>  |  - <facteur>  |  ( <expression> )
    Noeud* expBool(); // <expBool> ::= <relation> { <opOu> <relation> }
    Noeud* termeBool(); // <facteur>{<opEt><relation>}
    Noeud* relation(); //
    Noeud* terme(); //<terme> ::= <facteur> {<opAdd> <terme>} 
    Symbole opBool(); //  <opBool> ::= et|ou /
    Symbole opEt();
    Symbole opOu();
    Symbole opRel();
    Symbole opUnaire();
    Symbole opBinaire(); //  <opBinaire>  ::= + | - | *  | /
    Symbole opAdd(); //  <opAdd> ::= +|-
    Symbole opMult(); //<opMult> ::= *|/

    // outils pour se simplifier l'analyse syntaxique
    void testerSymCour(string ch); // si symbole courant != ch, erreur : on arrete le programme, sinon rien
    void sauterSymCour(string ch); // si symbole courant == ch, on passe au symbole suivant, sinon erreur : on arrete
    void erreur(string mess); // affiche les message d'erreur mess et arrete le programme
};

#endif /* LECTEURPHRASEAVECARBRE_H_ */
